package charRecognition;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.Vector;

import segmentation.CharInfo;
import utils.Constants;
import weka.classifiers.Classifier;
import weka.core.Instance;
import weka.core.Instances;
import weka.core.converters.ArffLoader;

public class WekaUtils {
	// Weka uses ".arff" files
	
	public static Vector<Character> classes = new Vector<Character>();
	
	public static void initClasses() {
		for (char c='a'; c<='z'; c++)
			classes.add(c);
		for (char c='A'; c<='Z'; c++)
			classes.add(c);
		for (char c='0'; c<='9'; c++)
			classes.add(c);
	}
	
	public static void printArffHeader(PrintWriter f, String s)
	{
		int numFeatures = CharInfo.getNumFeatures();
		
		f.println("@RELATION CAPTCHA");
		
		// features list
		for (int i=0; i<numFeatures; i++)
			f.println("@ATTRIBUTE feature_" + i + " NUMERIC");

		// create a string with class values
		StringBuilder class_values = new StringBuilder();
		class_values.append("{");
		class_values.append(s);
		class_values.append("}");
		
		// class attribute
		f.println("@ATTRIBUTE character "+class_values);
		
		// announce data
		f.println("@DATA");
		
	}
	
	public static void printArffHeader(PrintWriter f) {
		int numFeatures = CharInfo.getNumFeatures();
		
		f.println("@RELATION CAPTCHA");
		
		// features list
		for (int i=0; i<numFeatures; i++)
			f.println("@ATTRIBUTE feature_" + i + " NUMERIC");

		// create a string with class values
		StringBuilder class_values = new StringBuilder();
		class_values.append("{");
		for (Character c: classes) class_values.append(c + ", ");
		class_values.delete(class_values.length()-2, class_values.length());
		class_values.append("}");
		
		// class attribute
		f.println("@ATTRIBUTE character "+class_values);
		
		// announce data
		f.println("@DATA");
	}
	
	
	public static void writeInstanceToFile(PrintWriter f, double[] features, String classVal) {
		for (int i=0; i<features.length; i++)
			f.printf("%4.4f, ", features[i]);
		f.println(classVal);
	}

	public static Classifier deserializeModel(String file) throws FileNotFoundException, IOException, ClassNotFoundException {
		// deserialize model
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
		Classifier cls = (Classifier) ois.readObject();
		ois.close();
		return cls;
	}
		  
	public static void serializeModel(Classifier cls, String file) throws FileNotFoundException, IOException {
		// serialize model
		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
		oos.writeObject(cls);
		oos.flush();
		oos.close();
	}	
	
	public static Instances fetchData(String file) throws IOException {
		ArffLoader arffFile = new ArffLoader();
		arffFile.setFile(new File(file));
		arffFile.getStructure();
		Instances data = arffFile.getDataSet();
		return data;
	}

	public static Instances structure;
	public static Instances getStructure() throws IOException {
		if (structure == null) {
			ArffLoader arffFile = new ArffLoader();
			arffFile.setFile(new File(Constants.TRAIN_ARFF));
			structure = arffFile.getStructure();
		}
		structure.setClassIndex(CharInfo.getNumFeatures());
		return structure;
	}
	
	public static Instance getInstance(double[] v) throws IOException {
	    Instance inst = new Instance(getStructure().numAttributes());
	    inst.setDataset(getStructure());
	    
	    for (int i=0; i<v.length; i++) {
	    	inst.setValue(i, v[i]);
	    }
	    return inst;
	}

	public static Character getClass(double val) {
		return classes.get((int)val);
	}
}
